package cn.chenxing.utils;

import cn.chenxing.sftp.SFTP;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @Description SFTP的上传下载等
 * @Author maogen.ymg
 * @Date 2020/3/15 10:41
 */
@Slf4j
public class SftpUtil {
    private SftpUtil() {}

    /**
     * SFTP
     */
    private static SFTP channelSftp = new SFTP();

    /**
     * 获取远端存储目录
     */
    public static String getRemoteDirectory() {
        return channelSftp.getRemoteDirectory();
    }


    //---------------------------上传--------------------------//
    /**
     * 上传文件--文件路径
     * @param remoteDirectory 上传到远端的目录
     * @param remoteFileName  远端文件名
     * @param uploadFileUrl 要上传文件的路径
     */
    public static boolean upload(String remoteDirectory, String remoteFileName, String uploadFileUrl) {

        File file = new File(uploadFileUrl);
        try(FileInputStream fileInputStream = new FileInputStream(file)) {
            ChannelSftp sftp = channelSftp.getConnection();

            //如果文件夹不存在，则创建文件夹
            if(sftp.ls(remoteDirectory) == null){
                sftp.mkdir(remoteDirectory);
            }
            sftp.cd(remoteDirectory);

            sftp.put(fileInputStream, remoteFileName);

            log.info("[sftp] stringFilePath upload, path: {}", remoteDirectory + remoteFileName);
            return true;
        } catch (Exception e) {
            log.error("[sftp] stringFilePath upload failed{}", e.getMessage(), e);
            return false;
        }finally {
            channelSftp.disconnect();
        }
    }

    /**
     * 上传文件--byte[]
     * @param remoteDirectory 上传到远端的目录
     * @param remoteFileName 远端文件名
     * @param input 上传的文件
     * @return boolean
     */
    public static boolean upload(String remoteDirectory, String remoteFileName, byte[] input) {
        try(ByteArrayInputStream bis = new ByteArrayInputStream(input)){
            ChannelSftp sftp = channelSftp.getConnection();
            if(sftp.ls(remoteDirectory) == null){
                sftp.mkdir(remoteDirectory);
            }
            sftp.cd(remoteDirectory);

            sftp.put(bis, remoteFileName);
            log.info("[sftp] byteInput upload, path: {}", remoteDirectory + remoteFileName);
            return true;
        } catch (Exception e) {
            log.error("[sftp] byteInput upload failed{}", e.getMessage(), e);
            return false;
        }
        finally {
            channelSftp.disconnect();
        }
    }

    /**
     * 上传文件--InputStream
     * @param remoteDirectory 上传到远端的目录
     * @param remoteFileName 远端文件名
     * @param input 上传的文件
     * @return boolean
     */
    public static boolean upload(String remoteDirectory, String remoteFileName, InputStream input) {
        try {
            ChannelSftp sftp = channelSftp.getConnection();
            if(sftp.ls(remoteDirectory) == null){
                sftp.mkdir(remoteDirectory);
            }
            sftp.cd(remoteDirectory);
            sftp.put(input, remoteFileName);
            log.info("[sftp] inputStreamInput upload, path: {}", remoteDirectory + remoteFileName);
            return true;
        } catch (Exception e) {
            log.error("[sftp] inputStreamInput upload failed{}", e.getMessage(), e);
            return false;
        }
        finally {
            channelSftp.disconnect();
        }
    }


    //---------------------------下载--------------------------//
    /**
     * 下载文件 -- InputStream
     * @param remoteFilePath 远端文件路径
     * @return InputStream
     */
    public static InputStream downloadToStream(String remoteFilePath) {
        try{
            ChannelSftp sftp = channelSftp.getConnection();
            InputStream inputStream = sftp.get(remoteFilePath);
            log.info("[sftp] downloadToStream, path: {}", remoteFilePath);
            return inputStream;
        }catch (Exception e){
            log.error("[sftp] downloadToStream failed{}", e.getMessage(), e);
            return null;
        }finally {
            channelSftp.disconnect();
        }

    }

    /**
     * 下载文件 -- byte[]
     * @param remoteFilePath 远端文件路径
     * @return byte[]
     */
    public static byte[] downloadToBytes(String remoteFilePath) {
        ChannelSftp sftp = channelSftp.getConnection();
        try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); InputStream is = sftp.get(remoteFilePath)){

            byte[] buffs = new byte[4096];
            int len;
            while ((len = is.read(buffs)) != -1) {
                bos.write(buffs, 0, len);
            }

            byte[] fileData = bos.toByteArray();
            log.info("[sftp] downloadToBytes, path: {}", remoteFilePath);
            return fileData;

        }catch (Exception e){
            log.error("[sftp] downloadToBytes failed{}", e.getMessage(), e);
            return new byte[0];
        }finally {
            channelSftp.disconnect();
        }

    }

    /**
     * 下载文件
     * @param remoteFilePath 下载的文件完整目录
     * @param localSaveFile 存在本地的路径
     */
    public static File downloadToFile(String remoteFilePath, String localSaveFile) {
        File file = new File(localSaveFile);

        ChannelSftp sftp = channelSftp.getConnection();
        try(FileOutputStream fileOutputStream = new FileOutputStream(file)){

            sftp.get(remoteFilePath, fileOutputStream);
            log.info("[sftp] downloadToFile, remoteFilePath:{}, localSaveFilePath: {}", remoteFilePath, localSaveFile);
            return file;
        } catch (Exception e) {
            log.error("[sftp] downloadToFile failed{}", e.getMessage(), e);
            return null;
        }finally {
            channelSftp.disconnect();
        }
    }


    //---------------------------列出目录--------------------------//
    /**
     * 列出目录下的文件
     * @param directory 要列出的目录
     */
    public static List<String> ls(String directory) {

        try{
            ChannelSftp sftp = channelSftp.getConnection();
            Vector<ChannelSftp.LsEntry> list = sftp.ls(directory);

            List<String> fileNameList = new ArrayList<>();
            for (ChannelSftp.LsEntry lsEntry : list) {
                String fileName = lsEntry.getFilename();
                if (fileName.startsWith(".")) {
                    continue;
                }
                fileNameList.add(fileName);
            }
            log.info("[sftp] ls, path: " + directory);
            return fileNameList;

        }catch (Exception e){
            log.error("[sftp] ls failed{}", e.getMessage(), e);
            return new ArrayList<>();

        }finally {
            channelSftp.disconnect();
        }

    }


    //---------------------------更改文件名--------------------------//
    /**
     * 更改文件名
     * @param oldFilePath 旧文件名
     * @param newFilePath 新文件名
     */
    public static void rename(String oldFilePath, String newFilePath) {
        try {
            ChannelSftp sftp = channelSftp.getConnection();
            sftp.rename(oldFilePath, newFilePath);
            log.info("[sftp] rename, oldFilePath:{}, newFilePath: {}", oldFilePath, newFilePath);
        }catch (Exception e){
            log.error("[sftp] rename failed{}", e.getMessage(), e);
        }finally {
            channelSftp.disconnect();
        }
    }


    //---------------------------删除--------------------------//
    /**
     * 删除文件
     * @param remoteFilePath 要删除的文件
     */
    public static void rm(String remoteFilePath) {
        try{
            ChannelSftp sftp = channelSftp.getConnection();
            sftp.rm(remoteFilePath);
            log.info("[sftp] rm, path: {}", remoteFilePath);
        }catch (Exception e){
            log.error("[sftp] rm failed{}", e.getMessage(), e);
        }finally {
            channelSftp.disconnect();
        }

    }

    /**
     * 删除目录
     * @param remoteDirectoryPath 要删除目录
     */
    public static void rmdir(String remoteDirectoryPath) {
        try{
            ChannelSftp sftp = channelSftp.getConnection();
            sftp.rmdir(remoteDirectoryPath);
            log.info("[sftp] rmdir, path: {}", remoteDirectoryPath);
        }catch (Exception e){
            log.error("[sftp] rmdir failed{}", e.getMessage(), e);
        }finally {
            channelSftp.disconnect();
        }

    }

}
